/*
 * dhmm.h
 *
 *  Created on: Sep 19, 2011
 *      Author: tqlong
 */

#ifndef DHMM_H_
#define DHMM_H_

#include <armadillo>
#include <vector>
#include <ostream>

class DiscreteHMM
{
public:
  typedef std::vector<int> sequence_t;
  typedef struct JoinSequence {
    sequence_t oseq;  // observation
    sequence_t qseq;  // state
    void print() const;
    JoinSequence() {}
    JoinSequence(const sequence_t& o) : oseq(o) {}
  } joint_seq_t;
  typedef struct Variables {
    arma::mat alpha, beta;
    arma::vec ACC_start;
    arma::mat ACC_trans, ACC_emis;
  } variable_t;
  typedef std::vector<sequence_t> vseq_t;
public:
  void load(const char* fileName);
  void rand();
  void generate(int T, joint_seq_t &seq);
  double seq_probability(const sequence_t& o);
  double seq_probability_reverse(const sequence_t& o);
  void map(joint_seq_t& seq);
  void train(const vseq_t& data);

  int n_state() const { return start_.n_elem; }
  int n_observation() const { return emis_.n_rows; }
  void print_params() const;
public:
  arma::vec start_;
  arma::mat trans_, emis_;
  variable_t var_;
protected:
  void compute_alpha(const sequence_t& o, variable_t& var);
  void compute_beta(const sequence_t& o, variable_t& var);
  void accumulate(const sequence_t& o, double weight);
  void reestimate();
};

struct Log
{
  double s_;
  Log(double s) : s_(s) {}
};
std::ostream& operator<<(std::ostream&, const Log&);
double logadd(double a, double b);
double logsub(double a, double b);
double logsum_vec(arma::vec v);
double logsum(arma::mat v);
int discrete_sample(arma::vec p);

#endif /* DHMM_H_ */
